

#include "unity.h"
#include "unity_fixture.h"

#include "Debug.h"
#include "BSP_Sleep.h"
#include "log/log2.h"
#include <phNfcLib_Initialization.h>
#include "Utility.h"
#include <Reader/Reader.h>
#include <Reader/ReaderDesfire2.h>
//	#include <Reader/reader_wavelynx.h>
#include <Reader/reader_samav3.h>

/*============================================*/


extern phalMfdfEVx_SamAV3_NonX_DataParams_t  palMfdfEVx;	/* Pointer to MIFAREDESFire EVx data-params for SAM in S mode */
int reader_read_leaf(credential_t* cred);
#pragma pack(1)
//Access control Data
typedef struct {	
	uint8_t major;
	uint8_t minor;
	uint8_t customer_code[5];
	uint8_t credential_id[8];
	uint8_t access_data_format;
	uint8_t access_data_bit_length;
	uint8_t access_reader_data[16];
	uint8_t external_printed_number[8];
	uint8_t order_data[5];
	uint8_t reissue_code;
	uint8_t reserved[9];
	uint8_t secure_issuance_digital_signature[8];
	uint8_t reader_digital_signatures[80];
}acd_t;

#pragma pack()

/*============================================*/


TEST_GROUP(Leaf);


TEST_SETUP(Leaf)
{
	reader.hfFlags = TAG_MASK_MIFARE;
	Reader_NFC_LoadProfile(reader.hfFlags, 0, 0, 0);
}

TEST_TEAR_DOWN(Leaf)
{
	Reader_NFC_RfOff();
}


#if 1
static int clac_mac(const uint8_t *keys, uint8_t* data, uint16_t len, uint8_t* mac){
	void * pDataparam = phNfcLib_GetDataParams_Extended(PH_COMP_CRYPTOSYM, PH_NFCLIB_COMP_CRYPTOSYM_TYPE_ENC);
	phStatus_t  status = 0;

	status = phCryptoSym_LoadKeyDirect(pDataparam, keys, PH_KEYSTORE_KEY_TYPE_AES128);
	if(status){
		LOG2_ERR("phCryptoSym_LoadKeyDirect fail: %04X", status);
		return status;		
	}

	uint8_t aIV[PH_CRYPTOSYM_AES_BLOCK_SIZE];
    /* Load zero to IV */
    (void)memset(aIV, 0x00, PH_CRYPTOSYM_AES_BLOCK_SIZE);

    /* Load the IV. */
    status = phCryptoSym_LoadIv(
        pDataparam,
        aIV,
        PH_CRYPTOSYM_AES_BLOCK_SIZE);
    if(status){
		LOG2_ERR("phCryptoSym_LoadIv fail: %04X", status);
		return status;
	}
	
	uint8_t len_mac = 0;
	status = phCryptoSym_CalculateMac(pDataparam, PH_EXCHANGE_DEFAULT, data, len, mac, &len_mac);
	if(status){
		LOG2_ERR("phCryptoSym_CalculateMac fail: %04X", status);
		return status;	
	}
	return status;
}

static int div_key(uint8_t *div, uint8_t dlen, uint8_t *key){
	uint8_t master_key_root[16];
	memset(master_key_root, 0x01, 16);
	master_key_root[0] = 0xDE;
	LOG2_BUF_INF("root_key", master_key_root, 16);
	phStatus_t status;
	void* pCrypto = phNfcLib_GetDataParams_Extended(PH_COMP_CRYPTOSYM, PH_NFCLIB_COMP_CRYPTOSYM_TYPE_DIVERSIFY);
	status = phCryptoSym_DiversifyDirectKey(
		pCrypto,
		PHAL_MFDFEVX_DIV_METHOD_CMAC,
		master_key_root,
		PH_KEYSTORE_KEY_TYPE_AES128,
		div,
		dlen,
		key
		);
	return status;
}

static void leaf_verify_mac(uint8_t* uid, acd_t* acd){
	uint8_t card_key_no = 1;
	uint8_t div[16];
	div[0] = 0x88;
	memcpy(&div[1], uid, 7);
	div[8] = 0x88;
	memcpy(&div[9], uid, 7);
	LOG2_BUF_INF("div: ", div, 16);
	uint8_t data[56 + 8] = {0};
	uint16_t dlen = sizeof(data);
	memcpy(data, acd, 56);
	LOG2_BUF_INF("data: ", data, 56);
	const uint8_t* signatures = &acd->reader_digital_signatures[(card_key_no - 1)*10] + 2;
	LOG2_BUF_INF("signatures: ", signatures, 8);
//		memcpy(data + 56, signatures, 8);

	uint8_t key_out[16];
	div_key(div, 16, key_out);
	
	LOG2_BUF_INF("div_key: ", key_out, 16);
	uint8_t mac[16];
	clac_mac(key_out, data, 56, mac);
	LOG2_BUF_INF("mac: ", mac, 8);
}


TEST(Leaf, read_leaf)
{
	int ret;
	phStatus_t	status = 0;
	credential_t cred;
	while(1){
		Reader_NFC_RfOff();
		BSP_Sleep_Ms(500);
		ret = Reader_NFC_DiscoveryStd3(&cred.tag, PHAC_DISCLOOP_POS_BIT_MASK_A, 5);
		if(ret){
			continue;
		}
		//get aids
		uint8_t* aids = NULL;
		uint8_t naid = 0;
		ret = Reader_MFDF_GetApplicationIDs(PH_EXCHANGE_DEFAULT, &aids, &naid);
		if(ret){
			LOG2_ERR("get aids fail: %04X", ret);
			continue;
		}
		//print aids
		for(int i = 0; i < naid*3; i += 3){
			LOG2_INF("aid: %02X%02X%02X", aids[i], aids[i+1], aids[i+2]);
		}
		
		ret = Reader_MFDF_SelectApplication(PHAL_MFDFEVX_SELECT_PRIMARY_APP, aids, NULL);
		if(ret){
			LOG2_ERR("select app(%02X%02X%02X) fail: %04X", aids[0], aids[1], aids[2], ret);
			continue;
		}
		//load key
		void* key_store = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
		uint8_t ver = 0;
		uint8_t keyNo = 1;
		uint8_t key_aes[16];
		memset(key_aes, 0x01, 16);
		key_aes[0] = 0xDE;
		LOG2_BUF_DBG("key_aes", key_aes, 16);
		phKeyStore_FormatKeyEntry(key_store, keyNo, PH_KEYSTORE_KEY_TYPE_AES128);
		phKeyStore_SetKeyAtPos(key_store, keyNo, 0,	 PH_KEYSTORE_KEY_TYPE_AES128, (uint8_t *)key_aes, ver);
		uint8_t PcdCapsIn[] = {0x00,0x00,0x00,0x00,0x00,0x00};
		uint8_t CapsOut[12];
		uint8_t div[16] = {0};
		memcpy(div, cred.tag.uid, 7);
		uint8_t dlen = 7;
		uint8_t key_no_card = 1;
//			ret = Reader_MFDF_AuthenticateEv2(PHAL_MFDFEVX_AUTH_FIRST, PHAL_MFDFEVX_DIV_METHOD_CMAC, keyNo, ver, key_no_card, div, dlen);
		ret = Reader_MFDF_AuthenticateEv2(
			   PHAL_MFDFEVX_AUTH_FIRST,
			   PHAL_MFDFEVX_DIV_METHOD_CMAC,
			   keyNo,
			   ver,
			   key_no_card,
			   div,
			   dlen,
			   6,
			   &PcdCapsIn[0],
			   &CapsOut[0],
			   &CapsOut[6]);
		if(ret){
			LOG2_ERR("auth fail: %04X", ret);
			continue;
		}
		LOG2_INF("auth sussecful!");
		//read acd from card
		uint8_t* pACD = NULL;
		uint16_t rlen = 0;
		uint8_t bFileNo = 2;
		uint8_t offset[3] = {0x00, 0x00, 0x00};
		uint8_t length[3] = {sizeof(acd_t), 0x00, 0x00};
		ret = Reader_MFDF_ReadData(PHAL_MFDFEVX_COMMUNICATION_ENC, PHAL_MFDFEVX_APPLICATION_CHAINING, bFileNo,
			offset, length, &pACD, &rlen);
		if(ret){
			LOG2_ERR("read data fail: %04X", ret);
			continue;
		}
		acd_t* acd = (acd_t*)pACD;
		LOG2_BUF_INF("cred", acd->credential_id, 8);
		LOG2_BUF_INF("acd", (uint8_t*)pACD, rlen);
		leaf_verify_mac(cred.tag.uid, acd);
	}
}
#endif 

#include "phApp_Init.h"

#define SAM_KVER_LEAF 		0x01


#if 1



int reader_read_leaf2(uint8_t *uid, uint8_t ulen, uint8_t aid[3]){
	phStatus_t status;
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
	/* Clear the console. */
	log_reset_level();
	LOG2_DBG("A Ticket is discovered \n");

	
	/* SelectApplication */
	LOG2_PRINT("\nDESFire Select application.");
	status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, 0x00, &aid[0], NULL);
	CHECK_SUCCESS(status);

	uint8_t div[32] = {0};
	uint8_t dlen = 0;
	memcpy(div, uid, ulen);
	dlen = ulen;
	LOG2_BUF_DBG("div", div, dlen);
	uint8_t key_no_card = 1;
	LOG2_INF("\nphalMfdfEVx_AuthenticateAES: \n");
	/*AES Authenticate First*/
	status = phalMfdfEVx_AuthenticateAES(
			pAlMfdfEVx,
			PHAL_MFDFEVX_DIV_METHOD_CMAC,
			SAM_KID_LEAF,
			SAM_KVER_LEAF,
			key_no_card,
			div,
			dlen);
	 CHECK_SUCCESS(status);
	 
	uint8_t bFileNo = 2;
	uint8_t Len[] = {sizeof(acd_t),0x00,0x00}; //LSB first!
	uint8_t Offset[] = {0x00,0x00,0x00};//LSB first!

	uint16_t RxLen = 0;

	uint8_t RxData[sizeof(acd_t)+16];
	uint8_t * pRxData = NULL;
	uint8_t rlen = 0;
	memset(RxData, 0, sizeof(RxData));
	LOG2_INF("\nDESfire read data: \n");
	status = phalMfdfEVx_ReadData(
			pAlMfdfEVx,
			PHAL_MFDFEVX_COMMUNICATION_ENC,
			PHAL_MFDFEVX_APPLICATION_CHAINING,
			bFileNo,
			&Offset[0],
			&Len[0],
			&pRxData,
			&RxLen
			);
	while((status & PH_ERR_MASK) == PH_ERR_SUCCESS_CHAINING){
		LOG2_PRINT("chaining\n");
		memcpy(RxData+rlen, pRxData, RxLen);
		rlen += RxLen;
		pRxData = NULL;
		RxLen = 0;
		status = phalMfdfEVx_ReadData(
				pAlMfdfEVx,
				PHAL_MFDFEVX_COMMUNICATION_ENC|PH_EXCHANGE_RXCHAINING,
				PHAL_MFDFEVX_APPLICATION_CHAINING,
				bFileNo,
				&Offset[0],
				&Len[0],
				&pRxData,
				&RxLen
				);
	}
	CHECK_SUCCESS(status);
	memcpy(RxData+rlen, pRxData, RxLen);
	rlen += RxLen;
	acd_t* acd = (acd_t*)RxData;
	LOG2_INF("access format:%d, access bit length: %d", acd->access_data_format, acd->access_data_bit_length);
	LOG2_BUF_INF("access reader data", acd->access_reader_data, 16);
	LOG2_BUF_INF("acd", (uint8_t*)RxData, rlen);
	return status;
}
#endif 


#if 0
TEST(Leaf, read_leaf2)
{
	int ret;
	phStatus_t	status = 0;
	credential_t cred;
	uint8_t keys[16];
	memset(keys, 0x01, 16);
	keys[0] = 0xDB;
	samav3_activate2();
	ret = samav3_load_key(SAM_KID_LEAF, keys, SAM_KVER_LEAF, SAM_KEY_CLASS_PICC, SAM_KEY_T_AES_128, 1);
	TEST_ASSERT_EQUAL(0, ret);	
	samav3_deactivate();
	while(1){
		Reader_NFC_RfOff();
		BSP_Sleep_Ms(500);
		ret = Reader_NFC_DiscoveryStd3(&cred.tag, PHAC_DISCLOOP_POS_BIT_MASK_A, 5);
		if(ret){
			continue;
		}
//			uint8_t aid[3] = {0xF5,0x1C,0xDE};
		uint32_t aid = 0xF51CDB;
		samav3_activate2();
		ret = reader_read_leaf(&cred);
//			ret = reader_read_leaf2(cred.tag.uid, cred.tag.ulen, (uint8_t*)&aid);

		samav3_deactivate();
	}
}
#endif 


